<template>
  <div ref="scrollContainerRef" class="container">
    <!-- 下拉刷新指示 -->
    <ClientOnly>
      <div
        v-if="AstronautJSON"
        class="container-loading pullings-transform"
        :style="{ top: `-${spacing}px` }"
        :class="{
          'leave-transform': leave,
          'reset-transform': reset,
        }"
      >
        <Vue3Lottie
          :width="lottieWidth"
          :animationData="AstronautJSON"
          :autoPlay="false"
          :pauseAnimation="!pause"
        />
      </div>
      <!-- 页面内容插槽 -->
      <slot></slot>
    </ClientOnly>
  </div>
</template>

<script lang="ts" setup name="pullRefresh">
import { Vue3Lottie } from "vue3-lottie";
// import AstronautJSON from "~~/public/lottie/pullRefresh.json"; // 服务端警告
import { useEventListener, useScroll, useWindowScroll } from "@vueuse/core";
import { ref as vueRef, watchEffect } from "vue";
import { useGlobalStore } from "~~/store/global";
import { isiOS } from "@/utils";
import { useWindowSize } from "@vant/use";
import { useDevicePixelRatio, useFetch as http } from "@vueuse/core";

const props = withDefaults(
  defineProps<{
    // 加载状态
    loading?: boolean;
    // 动画时长
    duration?: number;
    // 间距 px
    topSpacing?: number;
  }>(),
  {
    loading: false,
    duration: 2000,
    topSpacing: 36,
  }
);

const emit = defineEmits(["refresh", "change", "update:loading"]);
// 获取窗口宽度和高度
const { width } = process.client ? useWindowSize() : { width: ref(320) };
const { pixelRatio } = useDevicePixelRatio();

// 容器实例
const scrollContainerRef = vueRef(null);

const globalStore = useGlobalStore();
// 状态栏高度: 默认 0
const statusBarHeight = computed(() => {
  if (!process.client) return 0;
  if (isiOS.value) {
    return globalStore.statusBarHeight || 0;
  } else {
    const zb = globalStore.statusBarHeight! / (width.value * pixelRatio.value);
    // const vw = `${zb * 100 || 0}vw`;
    const px = zb * width.value || 0;
    return px;
  }
});

/*********** 获取父容器：方案一 ***********/
// import { getCurrentInstance } from 'vue';
// const instance = getCurrentInstance();
// const parentComponentInstance = instance.parent;
// parentComponentInstance.vnode.el.scrollTop // 父级别的 scrollTop
/*********** 方案一 end ***********/

/*********** 获取父容器：方案二 ***********/
const parentElement = computed(() => {
  return (scrollContainerRef as any).value.parentElement;
});
/*********** 方案一 end ***********/

// 属性
let startY = 0;
let endY = 0;
// 动画宽
const lottieWidth = ref(60);
const AstronautJSON = ref();
// 是否暂停
const pause = ref(false);
// 指定间隔触发动画
const spacing = computed(
  () => lottieWidth.value + statusBarHeight.value + 44 + props.topSpacing
);
// 滑动偏移量
const pullings = ref(0);
const pullingsPx = computed(() => {
  if (props.loading) {
    return `${spacing.value}px`;
  }
  return `${pullings.value}px`;
});
// 是否重置状态
const reset = ref(false);
// 离开动画
const leave = ref(false);
// 是否重置完成
const isResetDone = ref(true);

// 父级可以滚动的最大距离: 这个用来预留上拉加载功能
// const scrollSpace = computed(() => {
//   return parentElement.value.scrollHeight - height.value;
// });

// 监听 touchstart 事件
useEventListener(scrollContainerRef, "touchstart", (e) => {
  const touch = e.touches[0];
  startY = touch.clientY;
});

// 监听 touchmove 事件
useEventListener(
  scrollContainerRef,
  "touchmove",
  (e) => {
    const touch = e.touches[0];
    endY = touch.clientY;
    // console.log(startY, "--endY--", endY, "--", endY - startY);
    if (!props.loading && isResetDone.value == true) {
      if (endY - startY <= spacing.value && endY - startY > 0) {
        pullings.value = endY - startY;
        emit("change", {
          status: "pulling",
          distance: endY - startY,
        });
      }
      if (reset.value !== false) reset.value = false;
      if (leave.value !== false) leave.value = false;
      if (pause.value !== false) pause.value = false;
    }
  },
  { passive: true }
);

// 监听 touchend 事件
useEventListener(scrollContainerRef, "touchend", () => {
  // console.log("--1", parentElement.value.scrollTop);
  // console.log("--2", (scrollContainerRef as any).value.scrollTop);

  // 如果下拉距离足够，并且容器滚动位置在顶部
  if (
    parentElement.value.scrollTop === 0 &&
    endY - startY > spacing.value &&
    (scrollContainerRef as any).value.scrollTop === 0 &&
    !props.loading &&
    isResetDone.value == true
  ) {
    pause.value = true;
    emit("update:loading", true);
    emit("change", {
      status: "loosing",
      distance: endY - startY,
    });
  } else if (
    parentElement.value.scrollTop === 0 &&
    endY - startY < spacing.value &&
    (scrollContainerRef as any).value.scrollTop === 0 &&
    !props.loading
  ) {
    reset.value = true;
  }
});

watch(
  () => props.loading,
  (newVal) => {
    if (newVal === false) {
      emit("change", {
        status: "normal",
        distance: 0,
      });
      leave.value = true;
      setTimeout(() => {
        pullings.value = 0;
        isResetDone.value = true;
      }, 750);
    } else if (newVal === true) {
      emit("refresh");
      isResetDone.value = false;
    }
  }
);
onBeforeMount(() => {
  http('https://bdc.btcdana.org/fx/lottie/pullRefresh.json').then((res) => {
    if (res.data.value)
      AstronautJSON.value = JSON.parse(res.data.value as string);
  });
});
</script>

<style lang="scss" scoped>
@keyframes leave {
  from {
    transform: translate(-50%, 0) translateY(v-bind("pullingsPx")) scale(1);
  }
  to {
    transform: translate(-50%, 0) translateY(v-bind("pullingsPx")) scale(0.001);
  }
}
@keyframes reset {
  from {
    transform: translate(-50%, 0) translateY(v-bind("pullingsPx"));
  }
  to {
    transform: translate(-50%, 0) translateY(0);
  }
}

.container {
  position: relative;
  width: 100vw;
  height: 100%;
  &-loading {
    z-index: 99;
    position: absolute;
    left: 50%;
    transform: translate(-50%, 0);
  }
}
.pullings-transform {
  transform: translate(-50%, 0) translateY(v-bind("pullingsPx"));
}

.reset-transform {
  animation: reset 0.75s 1 forwards;
}
.leave-transform {
  animation: leave 0.75s 1 forwards;
}
</style>
